package com.own.component.elastic.entity;

import co.elastic.clients.elasticsearch._types.aggregations.DateHistogramAggregation;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.RangeQuery;
import co.elastic.clients.json.JsonData;
import co.elastic.clients.util.ObjectBuilder;
import com.own.component.common.base.entity.BaseQuery;
import com.own.component.common.exception.BusinessSimpleException;
import com.own.component.elastic.constant.CalendarIntervalConstant;
import com.own.component.util.time.LocalDateTimeUtil;
import com.own.constant.ConstantDateFormatPattern;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.Accessors;
import org.apache.commons.lang3.StringUtils;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.function.Function;

/**
 * BaseElasticVo
 *
 * @author chenxueli
 * @date 2022-09-03 20:01:34
 */
@Schema(title = "es搜索引擎对象")
@Getter
@Setter
@Accessors(chain = true)
@ToString
@NoArgsConstructor
public class BaseElasticQuery extends BaseQuery implements Serializable {

    @Schema(title = "上一页最后一个id", hidden = true)
    private String searchAfter;

    @Schema(title = "请求时间(start)文本")
    private String statsTimeTextStart;

    @Schema(title = "请求时间(end)文本")
    private String statsTimeTextEnd;

    @Schema(title = "请求时间(start)")
    private LocalDateTime statsTimeStart;

    @Schema(title = "请求时间(end)")
    private LocalDateTime statsTimeEnd;

    @Schema(title = "时间范围")
    private String interval;

    public <T extends BaseElasticQuery> BaseElasticQuery(@NonNull T query) {
        super(query);
        this.searchAfter = query.getSearchAfter();
    }

    /**
     * 处理查询时间信息
     */
    public void resolveStatsTime() {
        // 手动处理时间信息
        var startTime = StringUtils.isBlank(this.statsTimeTextStart)
                ? null
                : LocalDateTimeUtil
                .parse(
                        this.statsTimeTextStart,
                        ConstantDateFormatPattern.Pattern.DATETIME,
                        ConstantDateFormatPattern.Pattern.DATETIME_MM,
                        ConstantDateFormatPattern.Pattern.DATE
                );
        var endTime = StringUtils.isBlank(this.statsTimeTextEnd)
                ? null
                : LocalDateTimeUtil
                .parse(
                        this.statsTimeTextEnd,
                        ConstantDateFormatPattern.Pattern.DATETIME,
                        ConstantDateFormatPattern.Pattern.DATETIME_MM,
                        ConstantDateFormatPattern.Pattern.DATE
                );
        // 设置时间信息
        var now = LocalDateTime.now();
        startTime = startTime == null ? now : startTime;
        endTime = endTime == null ? now : endTime;
        if (!endTime.isAfter(startTime)) {
            throw new BusinessSimpleException("时间范围不合法");
        }
        this.statsTimeStart = startTime;
        this.statsTimeEnd = endTime;
        this.statsTimeTextStart = LocalDateTimeUtil.format(startTime, ConstantDateFormatPattern.Pattern.DATETIME);
        this.statsTimeTextEnd = LocalDateTimeUtil.format(endTime, ConstantDateFormatPattern.Pattern.DATETIME);
    }

    /**
     * 构造时间信息查询条件
     *
     * @param field 字段信息
     * @return 查询条件
     */
    public Function<DateHistogramAggregation.Builder, ObjectBuilder<DateHistogramAggregation>> buildDateHistogramAggregation(String field) {
        // 执行信息查询
        var info = CalendarIntervalConstant.getDateHistogramInfo(this.interval);
        return builder -> builder
                .field(field)
                .calendarInterval(info.getInterval())
                .format(info.getFormat())
                .timeZone("Asia/Shanghai");
    }

    /**
     * 追加时间查询条件
     *
     * @param builder 查询构造器
     * @param field   字段信息
     */
    public void appendStatsQuery(BoolQuery.Builder builder, String field) {
        if (this.statsTimeStart != null) {
            builder.filter(RangeQuery.of(r -> r.field(field).gte(JsonData.of(ZonedDateTime.of(this.statsTimeStart, ZoneId.systemDefault()))))._toQuery());
        } else {
            if (StringUtils.isNotBlank(this.statsTimeTextStart)) {
                var requestTimeStart = LocalDateTimeUtil.parse(
                        this.statsTimeTextStart,
                        ConstantDateFormatPattern.Pattern.DATETIME,
                        ConstantDateFormatPattern.Pattern.DATETIME_MM,
                        ConstantDateFormatPattern.Pattern.DATE
                );
                builder.filter(RangeQuery.of(r -> r.field(field).gte(JsonData.of(ZonedDateTime.of(requestTimeStart, ZoneId.systemDefault()))))._toQuery());
            }
        }
        if (this.statsTimeEnd != null) {
            builder.filter(RangeQuery.of(r -> r.field(field).lte(JsonData.of(ZonedDateTime.of(this.statsTimeEnd, ZoneId.systemDefault()))))._toQuery());
        } else {
            if (StringUtils.isNotBlank(this.statsTimeTextEnd)) {
                var requestTimeEnd = LocalDateTimeUtil.parse(
                        this.statsTimeTextEnd,
                        ConstantDateFormatPattern.Pattern.DATETIME,
                        ConstantDateFormatPattern.Pattern.DATETIME_MM,
                        ConstantDateFormatPattern.Pattern.DATE
                );
                builder.filter(RangeQuery.of(r -> r.field(field).lte(JsonData.of(ZonedDateTime.of(requestTimeEnd, ZoneId.systemDefault()))))._toQuery());
            }
        }
    }

}
